/***********************************
 * Cipher Support Class - Singleton
 * This is a class that Matt Kunkel wrote for 
 * Internet Security and Privacy in the Spring of 2012
 * It is a basic implementation of the AutoKey cipher and constructs a shared key 
 * by using the phone numbers of the two parties
 * 
 */
package edu.csuohio.mad.ssmk.subtxt;

public class CipherSupport {

	private static CipherSupport instance = null;
	private static final int KeyLength = 10;
	private String PlainText;
	private String CipherText;
	private String KeySender;
	private String KeyReceiver;
	private int[] Key = new int[KeyLength];

	protected CipherSupport() {
	}

	// Singleton class, obviously requires a way to get a reference to it.
	public static CipherSupport getInstance() {
		if (instance == null)
			instance = new CipherSupport();
		return instance;
	}

	// Sets the plaintext prior to encryption
	public void setPlainText(String plain) {
		PlainText = plain;
	}

	// Returns the plaintext post decryption
	public String getPlainText() {
		return PlainText;
	}

	// Sets the ciphertext prior to encryption
	public void setCipherText(String cipher) {
		CipherText = cipher;
	}

	// Returns the ciphertext post decryption
	public String getCipherText() {
		return CipherText;
	}

	// sets the sender's key
	public void setKeySender(String ks) {
		KeySender = ks;
	}

	// returns the sender's key
	public String getKeySender() {
		return KeySender;
	}

	// sets the recipient's key
	public void setKeyReceiver(String kr) {
		KeyReceiver = kr;
	}

	// returns the recipient's key
	public String getKeyReceiver() {
		return KeyReceiver;
	}

	// encrypts the plaintext by first building the shared key
	// then it encrypts with autokey
	public void encrypt() {
		buildKey();
		encryptAutokey();
	}

	// decrypts the ciphertext by first building the shared key
	// then it decrypts with autokey
	public void decrypt() {
		buildKey();
		decryptAutokey();
	}

	// this is the meat of the autokey cipher, 
	// plenty of information about it is available online
	// thus i won't go into detail
	private void encryptAutokey() {
		char[] chrs = PlainText.toCharArray();
		int[] AutoKey = new int[KeyLength];
		System.arraycopy(Key, 0, AutoKey, 0, KeyLength);

		int chr, k = 0;
		for (int c = 0; c < chrs.length; c++) {
			chr = (int) chrs[c];
			if ((chr > 64 && chr < 91) || (chr > 96 && chr < 123)) {
				chrs[c] = encryptChar(chr, AutoKey[k]);
				if (chr > 64 && chr < 91)
					AutoKey[k] = chr - 65;
				else
					AutoKey[k] = chr - 97;
				k++;
				if (k == KeyLength)
					k = 0;
			}
		}
		CipherText = new String(chrs);
	}

	private void decryptAutokey() {
		char[] chrs = CipherText.toCharArray();
		int[] AutoKey = new int[KeyLength];
		System.arraycopy(Key, 0, AutoKey, 0, KeyLength);

		int chr, k = 0;
		for (int c = 0; c < chrs.length; c++) {
			chr = (int) chrs[c];
			if ((chr > 64 && chr < 91) || (chr > 96 && chr < 123)) {
				chrs[c] = decryptChar(chr, AutoKey[k]);
				if (chr > 64 && chr < 91)
					AutoKey[k] = chrs[c] - 65;
				else
					AutoKey[k] = chrs[c] - 97;
				k++;
				if (k == KeyLength)
					k = 0;
			}
		}
		PlainText = new String(chrs);
	}

	private char encryptChar(int chr, int offset) {
		if (chr > 64 && chr < 91)
			chr = ((chr - 65 + offset + 26) % 26) + 65;
		else if (chr > 96 && chr < 123)
			chr = ((chr - 97 + offset + 26) % 26) + 97;
		return (char) chr;
	}

	private char decryptChar(int chr, int offset) {
		if (chr > 64 && chr < 91)
			chr = ((chr - 65 - offset + 26) % 26) + 65;
		else if (chr > 96 && chr < 123)
			chr = ((chr - 97 - offset + 26) % 26) + 97;
		return (char) chr;
	}

	// builds the shared key by adding each respective digit of the sender and receiver's phone numbers
	private void buildKey() {
		for (int i = 0; i < KeyLength; i++)
			Key[i] = Integer.parseInt(String.valueOf(KeySender.charAt(i)))
					+ Integer.parseInt(String.valueOf(KeyReceiver.charAt(i)));
	}
}
